package cn.tedu.charging.order.service.impl;

import cn.tedu.charging.common.pojo.JsonResult;
import cn.tedu.charging.common.pojo.UserInfoVO;
import cn.tedu.charging.common.pojo.param.GunStatusUpdateParam;
import cn.tedu.charging.common.pojo.vo.StationInfoVO;
import cn.tedu.charging.order.constant.Constants;
import cn.tedu.charging.order.constant.MqttConstant;
import cn.tedu.charging.order.dao.repository.OrderRepository;
import cn.tedu.charging.order.feign.DeviceClient;
import cn.tedu.charging.order.feign.UserClient;
import cn.tedu.charging.order.mqtt.MqttProducer;
import cn.tedu.charging.order.pojo.dto.ChargingDTO;
import cn.tedu.charging.order.pojo.dto.OrderMQDTO;
import cn.tedu.charging.order.pojo.dto.StationInfoDto;
import cn.tedu.charging.order.pojo.dto.UserInfoDto;
import cn.tedu.charging.order.pojo.param.OrderAddParam;
import cn.tedu.charging.order.quartz.DeviceCheckJob;
import cn.tedu.charging.order.rabbit.RabbitMQOrderProducer;
import cn.tedu.charging.order.service.OrderService;
import cn.tedu.charging.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.quartz.SchedulerException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@Scope("")
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderRepository orderRepository;

    /**
     * 1.生成订单号
     * 2.获取场站信息和设备信息
     * 3.获取用户车辆信息
     * 4.给设备发送开始充电指令
     * 5.修改充电桩的状态 为 使用中
     * @param orderAddParam
     * @return
     */
    @Override
    public String createOrder(OrderAddParam orderAddParam) {
        // 创建订单服务风格 自顶向下编程
        // 1.生成订单号
        String orderNo = getOrderNo();

        // 2.获取场站信息和设备信息（充电枪id）
        StationInfoDto stationInfoDto = getStationInFoByGunId(orderAddParam.getGunId());

        // 3.获取用户车辆信息（用户id）
        UserInfoDto userInfoDto = getUserInfoByUserId(orderAddParam.getUserId());

        // 4.修改充电桩的状态 为 使用中（充电枪id）
        Boolean success = updateGunStatusBusy(orderAddParam.getGunId());

        // 5.创建自检任务
        log.debug("创建设备自检任务，入参:订单号：{},枪id：{}",orderNo,orderAddParam.getGunId());
        try {
//            DeviceCheckJob deviceCheckJob = new DeviceCheckJob(orderNo, orderAddParam.getGunId());
            DeviceCheckJob deviceCheckJob = new DeviceCheckJob(orderRepository, orderNo, orderAddParam.getGunId());
        } catch (SchedulerException e) {
            // 可以抛出一个业务异常，通过全局异常处理器处理
            // 告诉用户 给用户提示消息，订单创建失败，不要提示具体代码信息异常
            log.error("设备自检任务创建失败");
        }


        // 6.给设备发送开始充电指令（订单号，充电桩id，充电枪id）
        startCharing(orderNo,orderAddParam.getPileId(),orderAddParam.getGunId());

        // 7.给RabbitMQ发送延迟消息，用来处理设备故障导致的超时订单
        sendOrderMessage(orderNo);
        return orderNo;
    }

    @Autowired
    private RabbitMQOrderProducer rabbitMQOrderProducer;

    /**
     * 给RabbitMQ发送延迟消息，用来处理设备故障导致的超时订单
     */
    private void sendOrderMessage(String orderNo){
        OrderMQDTO orderMQDTO = new OrderMQDTO();
        orderMQDTO.setOrderNo(orderNo);
        rabbitMQOrderProducer.sendOrder(orderMQDTO);
    }


    @Autowired
    private MqttProducer mqttProducer;
    /**
     * 给设备发送开始充电指令
     * @param orderNo
     * @param pileId
     * @param gunId
     */
    private void startCharing(String orderNo, Integer pileId, Integer gunId) {
        // topic 前缀 + 桩id 不加枪的id，设备去订阅这个topic，接收所有发到这个桩上的消息
        String topic = MqttConstant.TOPIC_START_CHARGE_PREFIX + "/" + pileId;
        ChargingDTO chargingDTO = new ChargingDTO();
        chargingDTO.setOrderNo(orderNo);
        chargingDTO.setPileId(pileId);
        chargingDTO.setGunId(gunId);
        chargingDTO.setMsg(Constants.START_CHARGING);
        String json = JsonUtils.toJson(chargingDTO);   // 序列化成JSON字符串
        log.debug("订单服务发送开始充电指令到设备topic:{},消息:{}",topic,json);
        Boolean send = mqttProducer.send(topic, json);
        log.debug("订单服务发送开始充电指令到设备topic:{},消息:{},结果:{}",topic,json,send);
        // 如果发送失败，需要重试，需要告警
    }

    @Autowired
    private DeviceClient deviceClient;
    /**
     * 修改充电桩的状态 为 使用中
     * @param gunId
     * @return
     */
    private Boolean updateGunStatusBusy(Integer gunId) {
        GunStatusUpdateParam param = new GunStatusUpdateParam();
        param.setGunId(gunId);
        param.setStatus(Constants.GUN_STATS_BUSY);
        JsonResult<Boolean> jsonResult = deviceClient.updateGunStatus(param);
        if (jsonResult != null){
            return jsonResult.getData();
        }
        return false;
    }

    @Autowired
    private UserClient userClient;
    /**
     * 获取用户车辆信息
     * 订单服务调用用户服务的什么来获取信息？用户的接口
     * @param userId
     * @return
     */
    private UserInfoDto getUserInfoByUserId(Integer userId) {
        JsonResult<UserInfoVO> userCarInfo = userClient.getUserCarInfo(userId);
        if (userCarInfo != null){
            UserInfoVO data = userCarInfo.getData();
            if (data != null){
                UserInfoDto userInfoDto = new UserInfoDto();
                userInfoDto.setCarId(data.getCarId());
                return userInfoDto;
            }
        }
        return null;
    }

    /**
     * 根据枪编号获取场站信息
     * @param gunId
     * @return
     */
    private StationInfoDto getStationInFoByGunId(Integer gunId) {
        JsonResult<StationInfoVO> stationInfo = deviceClient.getStationInfo(gunId);
        if (stationInfo != null){
            StationInfoVO data = stationInfo.getData();
            System.out.println(data);
            if (data != null){
                StationInfoDto stationInfoDto = new StationInfoDto();
                // TODO copyProperties 底层实现
                BeanUtils.copyProperties(data,stationInfoDto);
                return stationInfoDto;
            }
        }
        return null;
    }

    /**
     * 生成订单号
     * @return
     */
    private String getOrderNo() {
        return "666";
    }

}